package web

import (
	"errors"
	"html/template"
	"os"
	"path/filepath"
	"strings"

	"xp/lib/etc"
	"xp/lib/log"
	"xp/lib/md"
	"xp/lib/mux"
)

type Templates struct {
	*template.Template

	root   string
	suffix string
}

var (
	errInvalidArgument = errors.New("invalid func argument")
)

func funcGetMap(keyvals ...interface{}) (map[string]interface{}, error) {
	if len(keyvals)%2 != 0 {
		return nil, errInvalidArgument
	}
	var dest = make(map[string]interface{})
	for i := 0; i < len(keyvals); i += 2 {
		if v, ok := keyvals[i].(string); ok {
			dest[v] = keyvals[i+1]
		}
	}
	dest["__version"] = md.GetRevision()
	return dest, nil
}

func (t *Templates) load() error {
	var files []string
	if err := filepath.Walk(t.root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		// 后缀名称检查
		if !strings.HasSuffix(path, t.suffix) {
			return nil
		}
		// 忽略临时文件或隐藏文件
		if filepath.Base(path)[0] == '.' {
			return nil
		}
		files = append(files, path)
		return nil
	}); err != nil {
		return err
	}
	tpl, err := template.New("xp").Funcs(template.FuncMap{
		"getMap": funcGetMap,
	}).ParseFiles(files...)
	if err != nil {
		return err
	}
	t.Template = tpl
	return nil
}

var (
	tpls *Templates
)

func LoadTemplate(dir, suffix string) error {
	if tpls == nil {
		tpls = &Templates{root: dir, suffix: suffix}
	}
	return tpls.load()
}

var (
	contentTypeHtml = []byte(`text/html`)
)

func Template(ctx *mux.Ctx, name string, data interface{}) {
	if tpls == nil {
		return
	}

	if etc.ModeDev() {
		tpls.load()
	}

	if data == nil {
		data = make(map[string]interface{})
	}
	if v, ok := data.(map[string]interface{}); ok {
		v["__version"] = md.GetRevision()
	}

	ctx.SetContentTypeBytes(contentTypeHtml)
	ctx.Response.Header.Set("X-XSS-Protection", "1; mode=block")
	ctx.Response.Header.Set("X-Frame-Options", "DENY")
	if err := tpls.ExecuteTemplate(ctx, name, data); err != nil {
		log.Warn("req_id", ctx.ReqID(), "err", err.Error(), "name", ctx.Name())
		ctx.Status(500, []byte(`execute template error`))
	}
}
